const cvs = document.getElementById("cvs");
const ctx = cvs.getContext("2d");
const width = cvs.width;
const height = cvs.height;

const winBoard = document.getElementById("winBoard");

const ROWS = 9;
const COLS = 9;
const RADIUS = 20;
const BLACKCOLOR = "#333";
const WHITECOLOR = "#eee";
const WINLIMIT = 5;

const rowGap = height / ROWS;
const colGap = width / COLS;
const statusMap = new Array(ROWS + 1)
  .fill()
  .map((item) => new Array(COLS + 1).fill(0));

let colsId, rowsId;

let isBlack = true;

function drawBackground() {
  ctx.beginPath();
  for (let i = 0; i <= ROWS; i++) {
    drawLine(
      { font: "38px Arial", strokeStyle: "#000" },
      [0, rowGap * i],
      [width, rowGap * i]
    );
  }
  for (let j = 0; j <= COLS; j++) {
    drawLine(
      { font: "38px Arial", strokeStyle: "#000" },
      [colGap * j, 0],
      [colGap * j, height]
    );
  }
  ctx.closePath();
}

function drawLine(config, point1, point2) {
  ctx.font = config.font;
  ctx.strokeStyle = config.strokeStyle;
  ctx.moveTo(...point1);
  ctx.lineTo(...point2);
  ctx.stroke();
}

function drawPiece(point) {
  colsId = Math.round(point[0] / colGap);
  rowsId = Math.round(point[1] / rowGap);
  let px = colsId * colGap;
  let py = rowsId * rowGap;
  ctx.beginPath();
  ctx.fillStyle = isBlack ? BLACKCOLOR : WHITECOLOR;
  ctx.moveTo(px, py);
  ctx.arc(px, py, RADIUS, 0, Math.PI * 2, true);
  ctx.fill();
  ctx.closePath();
}

function isInvalidPoint(point) {
  return point[0] < 0 || point[0] > COLS || point[1] < 0 || point[1] > ROWS;
}

function createJudgementFunc(np1, np2) {
  return (point) => {
    let nextP1 = np1(point);
    let nextP2 = np2(point);
    let curStatus = isBlack ? 1 : 2;
    let sum = 1;
    while (
      !isInvalidPoint(nextP1) &&
      statusMap[nextP1[0]][nextP1[1]] === curStatus
    ) {
      nextP1 = np1(nextP1);
      sum++;
    }
    while (
      !isInvalidPoint(nextP2) &&
      statusMap[nextP2[0]][nextP2[1]] === curStatus
    ) {
      nextP2 = np2(nextP2);
      sum++;
    }
    if (sum >= WINLIMIT) {
      return true;
    } else {
      return false;
    }
  };
}
function verWin(point) {
  return createJudgementFunc(
    (p) => {
      return [p[0] - 1, p[1]];
    },
    (p) => {
      return [p[0] + 1, p[1]];
    }
  )(point);
}
function horWin(point) {
  return createJudgementFunc(
    (p) => {
      return [p[0], p[1] - 1];
    },
    (p) => {
      return [p[0], p[1] + 1];
    }
  )(point);
}
function diagWin(point) {
  return createJudgementFunc(
    (p) => {
      return [p[0] - 1, p[1] - 1];
    },
    (p) => {
      return [p[0] + 1, p[1] + 1];
    }
  )(point);
}
function revWin(point) {
  return createJudgementFunc(
    (p) => {
      return [p[0] - 1, p[1] + 1];
    },
    (p) => {
      return [p[0] + 1, p[1] - 1];
    }
  )(point);
}

function isWin(point) {
  return horWin(point) || verWin(point) || diagWin(point) || revWin(point);
}

function init() {
  winBoard.style.visibility = "hidden";
  ctx.clearRect(0, 0, width, height);
  drawBackground();
}

document.addEventListener("click", (e) => {
  drawPiece([e.clientX, e.clientY]);
  if (statusMap[rowsId][colsId] === 0) {
    statusMap[rowsId][colsId] = isBlack ? 1 : 2;
  }

  if (isWin([rowsId, colsId])) {
    winBoard.innerText = `${isBlack ? "black" : "white"} win!`;
    winBoard.style.visibility = "visible";
    setTimeout(() => {
      init();
    }, 1000);
  }
  isBlack = !isBlack;
});

init();
